package 线程andJUC.线程同步;


public class Synchronized {
    /*
    对于之前卖票问题，发现同一张票卖了两次，出现重复票，为解决这个问题，java提供了同步机制
    synchronized
    过程：窗口1在进行操作时，窗口2和窗口3只能在外面等着，窗口1操作结束，窗口1/2/3才有机会进入代码
    去执行。也就是说，在某个线程修改共享资源的时候，其他线程不能改变该资源，等待修改结束后，才可以抢夺cpu
    完成对应的操作，保证了数据的同步操作，解决了线程不同步的问题

    实现同步的方式：
    synchronized代码块
    synchronized方法付
    lock锁

    线程安全问题：public synchronized void method(){}

        同步代码块：public synchronized void method (){可能会产生线程安全问题的代码}
        同步方法锁的是整个方法的代码，执行效率没有同步代码块效率高
        同步方法锁的是谁？：
        非静态方法：this
        静态方法：当前类的class对象

     */

    /*
    同步代码块
    synchronized(同步锁){ 需要同步操作的代码  }
    同步锁知识一个概念，可以认为是在对象上标记了一个锁
    注意：在任何时候最多允许一个线程拥有同步锁就进入代码块，其他线程只能在外面等着

    锁对象可以是任何类型，但多个线程对象只能拥有一把锁
     */
    public static void main(String[] args) {
//        创建Runnable接口的实现类对象
        MyTicket mt=new MyTicket();
//        创建Thread类对象，构造方法传递Runnable接口的实现类对象
        Thread t0=new Thread(mt,"窗口1");
        Thread t1=new Thread(mt,"窗口2");
        Thread t2=new Thread(mt,"窗口3");
//        开启多线程
        t0.start();
        t1.start();
        t2.start();
    }


}

class MyTicket implements Runnable{
//  定义一个共享的票源
//    也可以使用  static ticket=100;
    private /* static */int ticket=100;
//    创建一个锁对象
    Object obj=new Object();

//  设置线程任务：卖票
    @Override
    public void run() {
//        使用死循环，让卖票操作重复执行
        while (true) {
        //    同步代码块
            synchronized (obj) {
                if (ticket > 0) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在售卖第" + ticket + "张票");
                    ticket--;
                }
            }
        }
    }
}
